#include "Communication.h"



MySql_DB     *g_pMySql;
ProcessOrder *g_pProcessOrder;



std::vector<UserNode>   UserOnlineList;
std::vector<DeviceNode> DeviceOlineList;

pthread_mutex_t mutex_UserOlineList;
pthread_mutex_t mutex_DeviceOlineList;
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
void CommunicationInit()
{
  pthread_mutex_init(&mutex_UserOlineList,NULL);
  pthread_mutex_init(&mutex_DeviceOlineList,NULL);

  //g_pMySql = new MySql_DB(SERVER_IP,USER_NAME , PASSWORD);
  //g_pMySql->ConnectToServer(DATABASE);

  g_pProcessOrder = new ProcessOrder();
  g_pProcessOrder->start();
}
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
void CommunicationDeInit()
{
  pthread_mutex_destroy(&mutex_UserOlineList);
  pthread_mutex_destroy(&mutex_DeviceOlineList);
}
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
BOOL SocketSend(int new_fd ,char*SendBuf,int Length)
{

               SendBuf[Length-2] = 0x0d;
               SendBuf[Length-1] = 0x0a;  //Attention : Must In Tail!
		      /*向连接的新套接字字符发送数据*/

		      if((send(new_fd, SendBuf, Length, 0)) < 0)  //
		      {
		        fprintf(stderr, "send error: %s\n", strerror(errno));
		        LOG(ERROR) << "send error:" << strerror(errno);

		        close(new_fd);
		        LOG(ERROR) << "服务器断开此无效连接";

		        return FALSE;
		      }

                 printf("Send %s OK\n",SendBuf);
                 LOG(INFO) << "send :" << SendBuf;

               return TRUE;
}
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/

BOOL SocketReceive(int new_fd , char ReadBuf[],int Length)
{
    memset(ReadBuf, 0 , Length);

   if((recv(new_fd, ReadBuf, Length , 0)) < 0)  //
          {
           fprintf(stderr, "recv error: %s\n", strerror(errno));
           LOG(ERROR) << "recv error: " << strerror(errno);

           close(new_fd);
           LOG(ERROR) << "服务器断开此无效连接";

           return FALSE;
          }

          printf("Receive %s OK\n",ReadBuf);
          LOG(INFO) << "Receive :" << ReadBuf;

       return TRUE;
}

/****************************
Function   : Communication
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
void Commynication(int p)
{
  int new_fd = p;

  LOG(INFO) << "建立新连接成功";

    switch(AskRole(new_fd))
  {
    case USER:    CommunicateWithUser(new_fd);  break;
    case DEVICE:  CommunicateWithDevice(new_fd);break;

    default: break;
  }

}
/****************************
Function   : Ask Linker's Role
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
short AskRole(int new_fd)
{
   char cReceiveBuf[MESSAGE_LENGTH];
   memset(cReceiveBuf,0,MESSAGE_LENGTH);

  if(SocketSend( new_fd ,SendOrder[ASK],MESSAGE_LENGTH) == FALSE)
  {
     return 0;
  }

  usleep(200*1000);

  if(SocketReceive( new_fd ,cReceiveBuf,MESSAGE_LENGTH) == FALSE)
  {
   return 0;
  }

  int Role = GetValue(cReceiveBuf,0,5) ;

   switch(Role)
   {
    case DEVICE :   LOG(INFO) << "连接者为设备";
                    return DEVICE;

    case USER   :   LOG(INFO) << "连接者为用户";
                    return USER;

    default     :   close(new_fd);
                    LOG(WARNING) << "不明连接者,服务器已断开此连接";
                    return 0;
   }

}

/****************************
Function   : Communication
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
BOOL CommunicateWithUser(int new_fd)
{
  char cReceiveBuf[MESSAGE_LENGTH];
  memset(cReceiveBuf,0,MESSAGE_LENGTH);

/***********************************  ID  **************************************/
  if(SocketSend( new_fd ,SendOrder[ID],MESSAGE_LENGTH) == FALSE)
  {
     return FALSE;
  }

  while(SocketReceive( new_fd ,cReceiveBuf,MESSAGE_LENGTH))
  {
      int nType = GetOrderType(cReceiveBuf);
      BOOL bNormal = TRUE;
      usleep(200*1000);
      switch(nType)
      {
        case ORDER_LOGIN        : bNormal = ProcessLogin(new_fd ,cReceiveBuf);  break;
        case ORDER_CONDEV       : bNormal = ProcessConDev(new_fd ,cReceiveBuf); break;
        case ORDER_CURTAIN_STATE: bNormal = ProcessCurState(new_fd ,cReceiveBuf); break;
        case ORDER_CURTAIN_MOVE : bNormal = ProcessCurMove(new_fd ,cReceiveBuf); break;

        default :bNormal = FALSE;
      }

      if(!bNormal)
      {
        close(new_fd);
        return FALSE;
      }
  }

}
/****************************
Function   : Communication
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
BOOL CommunicateWithDevice(int new_fd)
{
  char cReceiveBuf[MESSAGE_LENGTH];
  memset(cReceiveBuf,0,MESSAGE_LENGTH);

/***********************************  ID  **************************************/
  if(SocketSend( new_fd ,SendOrder[ID],MESSAGE_LENGTH) == FALSE)
  {
     return FALSE;
  }
  usleep(200*1000);
  if(SocketReceive( new_fd ,cReceiveBuf,MESSAGE_LENGTH) == FALSE)
  {
    return FALSE;
  }

    DeviceNode device;
    device.DeviceID = GetValue(cReceiveBuf, 0 , 4);
    device.new_fd   = new_fd;

    pthread_mutex_lock(&mutex_DeviceOlineList);    //lock
    DeviceOlineList.push_back(device);             //join in DeviceList
    pthread_mutex_unlock(&mutex_DeviceOlineList);  //unlock

    char chdeviceId[5] = {0};
    memcpy(chdeviceId , cReceiveBuf , 4);
    string strDeviceid = chdeviceId;
    if(!g_pProcessOrder->m_pMySql->SetDeviceStateById(chdeviceId, DeviceState_Free))
    {
      return FALSE;
    }

    stringstream   strStream ;
    strStream << new_fd;
    string strFd = strStream.str();
    if(!g_pProcessOrder->m_pMySql->SetDeviceConnectFdById(chdeviceId,strFd))
    {
      return FALSE;
    }

    LOG(INFO) << "此设备的设备号为 ：" << device.DeviceID;

//    while(1)
//    {
//      std::vector<DeviceNode>::iterator it;
//      pthread_mutex_lock(&mutex_DeviceOlineList);       //lock
//
//      for(it = DeviceOlineList.begin();it != DeviceOlineList.end(); it ++)
//      {
//        if(it->DeviceID == device.DeviceID)
//        {
//           pthread_mutex_unlock(&mutex_DeviceOlineList);//unlock
//           goto OUT;
//        }
//      }
//      close(new_fd);
//      pthread_mutex_unlock(&mutex_DeviceOlineList);     //unlock
//
//      LOG(ERROR) << "找不到设备，服务器已断开此无效连接";
//      break;
//
//OUT:
//        if(it->SendFlag == TRUE)                        //Has Message to Send
//      {
//
//            if(SocketSend( new_fd ,it->Sendbuf,MESSAGE_LENGTH) == FALSE)
//            {
//                  pthread_mutex_lock(&mutex_DeviceOlineList);        //lock
//                  DeviceOlineList.erase(it);
//                  pthread_mutex_unlock(&mutex_DeviceOlineList);      //unlock
//            }
//
//            it->SendFlag = FALSE;
//      }
//    }
}
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
BOOL ProcessLogin(int new_fd ,char recv[])
{

  vector<string> vstrParameters;
  string strParameters = recv + 10;
  strParameters = strParameters.substr(0 ,strParameters.size() - 2);
  vstrParameters = MySplit(strParameters,'|');

  if(vstrParameters.size() != 2)
  {
   LOG(ERROR) << "Move Parameters Error";
   return FALSE;
  }
   string strUserName = vstrParameters[0];
   string strPassword = vstrParameters[1];

   if(!g_pMySql->JudgeLogin(strUserName,strPassword))
   {
       if(SocketSend( new_fd ,SendOrder[REJECT],MESSAGE_LENGTH) == FALSE)
       {
          return FALSE;
       }
      LOG(ERROR) << "UserName Or Passwd is error";
      return FALSE;
   }
   if(SocketSend( new_fd ,SendOrder[ACK],MESSAGE_LENGTH) == FALSE)
   {
      return FALSE;
   }
   LOG(INFO) << "Login successful";
   return TRUE;
}
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
BOOL ProcessConDev(int new_fd ,char recv[])
{

  vector<string> vstrParameters;
  string strParameters = recv + 10;
  strParameters = strParameters.substr(0 ,strParameters.size() - 2);
  vstrParameters = MySplit(strParameters,'|');

  if(vstrParameters.size() != 1)
  {
   LOG(ERROR) << "Move Parameters Error";
   return FALSE;
  }

  string DeviceID = vstrParameters[0].c_str();

  LOG(INFO) << "此用户需要连接的设备号为：" << DeviceID;

  UserNode MyUser;
  pthread_mutex_lock(&mutex_DeviceOlineList);       //lock
  MyUser.DevicePosition = GetfdFromList( DeviceID,DeviceOlineList);
  pthread_mutex_unlock(&mutex_DeviceOlineList);       //lock
/**********************************  是否在线  ***********************************/
  if(MyUser.DevicePosition == -1)  //Not OnLine
  {

       if(SocketSend( new_fd ,SendOrder[OFF],MESSAGE_LENGTH) == FALSE)
       {
          return FALSE;
       }
       close(new_fd);
       LOG(ERROR) << "此用户需要连接的设备不在线，服务器已断开与此用户的连接";
       return FALSE;
  }

   if(SocketSend( new_fd ,SendOrder[ACK],MESSAGE_LENGTH) == FALSE)
   {
      return FALSE;
   }

   return TRUE;
}
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
BOOL ProcessCurState(int new_fd ,char recv[])
{
  vector<string> vstrParameters;
  string strParameters = recv + 10;
  strParameters = strParameters.substr(0 ,strParameters.size() - 2);
  vstrParameters = MySplit(strParameters,'|');

  if(vstrParameters.size() != 1)
  {
   LOG(ERROR) << "Move Parameters Error";
   return FALSE;
  }

   string DeviceID = vstrParameters[0].c_str();

   LOG(INFO) << "此用户需要连接的设备号为：" << DeviceID;

   UserNode MyUser;
   pthread_mutex_lock(&mutex_DeviceOlineList);       //lock
   MyUser.DevicePosition = GetfdFromList( DeviceID,DeviceOlineList);
/**********************************  是否在线  ***********************************/
  if(MyUser.DevicePosition == -1)  //Not OnLine
  {
       pthread_mutex_unlock(&mutex_DeviceOlineList);       //unlock
       if(SocketSend( new_fd ,SendOrder[OFF],MESSAGE_LENGTH) == FALSE)
       {
          return FALSE;
       }
       close(new_fd);
       LOG(ERROR) << "此用户需要连接的设备不在线，服务器已断开与此用户的连接";
       return FALSE;
  }
    ////////////////////////////////////////////////////////
      int i ;
      for( i = 0; i < CURTAIN_NUMBER ; i++)
      {
        SendOrder[ON][2+i] = DeviceOlineList[MyUser.DevicePosition].CurtainState[i];
      }

      SendOrder[ON][2+CURTAIN_NUMBER]   = '\r';
      SendOrder[ON][2+CURTAIN_NUMBER+1] = '\n';

      pthread_mutex_unlock(&mutex_DeviceOlineList);       //unlock
     if(SocketSend( new_fd ,SendOrder[ON],MESSAGE_LENGTH) == FALSE)
     {
        return FALSE;
     }
     LOG(INFO) << "发送此设备的每个窗帘的开闭状态";
   return TRUE;
}
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
BOOL ProcessCurMove(int new_fd ,char recv[])
{
  vector<string> vstrParameters;
  string strParameters = recv + 10;
  vstrParameters = MySplit(strParameters,'|');

  if(vstrParameters.size() != 3)
  {
   LOG(ERROR) << "Move Parameters Error";
   return FALSE;
  }

  string DeviceID = vstrParameters[0];

  UserNode MyUser;
  pthread_mutex_lock(&mutex_DeviceOlineList);       //lock
  MyUser.DevicePosition = GetfdFromList( DeviceID,DeviceOlineList);
/**********************************  是否在线  ***********************************/
  if(MyUser.DevicePosition == -1)  //Not OnLine
  {
      pthread_mutex_unlock(&mutex_DeviceOlineList);       //lock
       if(SocketSend( new_fd ,SendOrder[OFF],MESSAGE_LENGTH) == FALSE)
       {
          return FALSE;
       }
       LOG(ERROR) << "此用户需要连接的设备不在线，服务器已断开与此用户的连接";
       return FALSE;
  }


   int nPos   = atoi(vstrParameters[1].c_str()) - 1;
   char chState = vstrParameters[2][0];
   DeviceOlineList[MyUser.DevicePosition].CurtainState[nPos] = chState;

   DeviceOlineList[MyUser.DevicePosition].SendFlag = TRUE;
   pthread_mutex_unlock(&mutex_DeviceOlineList);       //lock
   if(SocketSend( new_fd ,SendOrder[ACK],MESSAGE_LENGTH) == FALSE)
   {
      return FALSE;
   }

  return true;
}
/****************************
Function   : Communication
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
int GetfdFromList(string DeviceID,std::vector<DeviceNode> DeviceList)
{
  int nSize = DeviceList.size();
  if(nSize == 0)
  {
     return -1;
  }
  int i = 0;

      for(i = 0 ;i < nSize ; i++)
      {
        if(DeviceList[i].DeviceID == DeviceID)
        {
           return i;
        }
      }
  return -1;
}
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
int GetValue(char arr[], int PosBegin , int Length) //
{
  int Value = 0;
  int i ;

  if(PosBegin < 0 || Length < 0) return -1;

  for( i = 0 ; i < Length ; i++)
  {
    if (arr[PosBegin+i] < '0' || arr[PosBegin+i] > '9')
    {
      return -1;
    }
    Value += (arr[PosBegin+i] - '0')*pow(10,Length - i -1);
  }

  return Value;
}
/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
int GetOrderType(char recv[])
{

  string strOrder;
  strOrder.resize(10);

  int i = 0;
  for(i = 0 ; i < 10 ; i++)
  {
    strOrder[i] = recv[i];
  }
  strOrder.erase(remove(strOrder.begin(), strOrder.end(), '.'), strOrder.end());
  if(strOrder == "login")
  {
    return ORDER_LOGIN;
  }
  if(strOrder == "condev")
  {
    return ORDER_CONDEV;
  }
   if(strOrder == "curstate")
  {
    return ORDER_CURTAIN_STATE;
  }
  if(strOrder == "curmove")
  {
    return ORDER_CURTAIN_MOVE;
  }
  return 0;

}

/****************************
Function   :
Parameter  :
ReturnValue:
Author     :
Data       :
****************************/
string strEraseAll(string str ,char chOut )
{
   str.erase(remove(str.begin(), str.end(), chOut), str.end());
   return str;
}
vector<string> MySplit(string v_Str, char v_chDelimiter)
{
	std::vector<std::string> vstrValue;
	std::string tmpstr;
	while (!v_Str.empty())
	{
		int ind = v_Str.find_first_of(v_chDelimiter);
		if (ind == -1)
		{
			vstrValue.push_back(v_Str);
			v_Str.clear();
		}
		else{

				if(ind != 0)
				{
				 vstrValue.push_back(v_Str.substr(0, ind));
				}
			   v_Str = v_Str.substr(ind + 1, v_Str.size() - ind - 1);
		    }
	}
	return vstrValue;
}
